package smetana.modules.ui.model;

import org.apache.commons.lang.builder.ReflectionToStringBuilder;
import org.apache.log4j.Logger;
import org.apache.pivot.util.ListenerList;

/**
 * @author dmitry.mamonov
 */
public class Cursor<T> {
    private final Logger log = Logger.getLogger(getClass());
    private T currentValue;
    private ConsumerListenerList<T> consumers = new ConsumerListenerList<T>();
    private ProducerListenerList<T> producers = new ProducerListenerList<T>();

    public Cursor() {
        super();
    }

    public void set(T newValue){
        log.info("Value is set: "+ ReflectionToStringBuilder.toString(newValue));
        this.currentValue=newValue;
        consumers.onCurrentSwitched(this);
    }

    public void update(T updatedValue){
        log.info("Update value: "+ ReflectionToStringBuilder.toString(updatedValue));
        this.currentValue = updatedValue;
        producers.onCurrentUpdated(this, updatedValue);
    }

    public void deleteCurrent(){
        log.info("Delete current, current: "+ ReflectionToStringBuilder.toString(currentValue));
        producers.onCurrentDeleted(this);
    }

    public void refreshFor(T targetValue) {
        log.info("Refresh for: "+ReflectionToStringBuilder.toString(targetValue));
        producers.onRefreshFor(this, targetValue);
    }


    public T get(){
        log.info("Get: "+ReflectionToStringBuilder.toString(currentValue));
        return currentValue;
    }

    public boolean hasValue(){
        log.info("Has value: "+currentValue);
        return currentValue!=null;
    }

    public ConsumerListenerList<T> getConsumers() {
        return consumers;
    }

    public ProducerListenerList<T> getProducers() {
        return producers;
    }

    public interface Consumer<IT> {
        void onCurrentSwitched(Cursor<IT> cursor);
    }

    public class ConsumerListenerList<P> extends ListenerList<Consumer<P>>
            implements Consumer<P> {
        @Override
        public void onCurrentSwitched(Cursor<P> cursor) {
            for(Consumer<P> consumer:this){
                consumer.onCurrentSwitched(cursor);
            }
        }
    }

    public interface Producer<IT>{
        void onCurrentUpdated(Cursor<IT> cursor, IT updatedValue);
        void onCurrentDeleted(Cursor<IT> cursor);
        void onRefreshFor(Cursor<IT> cursor, IT targetValue);
    }

    public class ProducerListenerList<P> extends ListenerList<Producer<P>>
            implements Producer<P> {
        @Override
        public void onCurrentUpdated(Cursor<P> cursor, P updatedValue) {
            for(Producer<P> producer:this){
                producer.onCurrentUpdated(cursor, updatedValue);
            }
        }

        @Override
        public void onCurrentDeleted(Cursor<P> cursor) {
            for(Producer<P> producer:this){
                producer.onCurrentDeleted(cursor);
            }
        }

        @Override
        public void onRefreshFor(Cursor<P> cursor, P targetValue) {
            for(Producer<P> producer:this){
                producer.onRefreshFor(cursor, targetValue);
            }
        }
    }

}